/**
*  Copyright (c) 2011, Alex Theodoridis
*  All rights reserved.

*  Redistribution and use in source and binary forms, with
*  or without modification, are permitted provided that the
*  following conditions are met:
*  Redistributions of source code must retain the above
*  copyright notice, this list of conditions and the following disclaimer.
*  Redistributions in binary form must reproduce the above
*  copyright notice, this list of conditions and the following
*  disclaimer in the documentation and/or other materials
*  provided with the distribution.

*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
*  AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
*  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
*  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
*  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
*  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE,
*  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*/

#include <NeuralNetwork/Perceptron/PerceptronNeuralNetwork.h>
#include <NeuralNetwork/LearningAlgorithm//BackPropagation/BepAlgorithm.h>
#include <stdio.h>
#include "TrainingExecutionListener.h"
#include <NeuralNetwork/Neuron/Equation/SigmaEquationFactory.h>
#include <NeuralNetworkXmlSerializer/XmlPerceptronStream.h>
#include <Utilities/StrUtil/StrUtil.h>
#include <Utilities/Design/Strategy.h>
#include <Utilities/Design/Singleton.h>

using namespace nn;
using namespace bp;
using namespace std;
using namespace utils;

template<class Var>
class XmlVarStream : public IXmlVarStream<Var> {

    bool serialize(const float& var, TiXmlText** text) {
        std::string str = utils::StrUtil::lexical_cast<std::string,Var > (var);
        (*text) = new TiXmlText(str.c_str());
        return true;
    }

    Var deserialize(const TiXmlElement* text) {
        return utils::StrUtil::lexical_cast<Var, std::string>(text->GetText());
    }
};

/*
 *
 */
int main(int argc, char** argv) {
    utils::SharedPtr< PerceptronNeuralNetwork<float> > perceptron = new PerceptronNeuralNetwork<float> (2, new nn::SigmaEquationFactory<float>, 1);
    perceptron->addLayer(2);
    perceptron->addLayer(3);
    
    //perceptron->addLayer(2);
    NNVar d(20);
    NNSamplesSet<float> newData(2, 1);
    std::vector< NNSamplesSet<float> > data;

    std::vector<int> myData;
    myData.resize(100, 0);

    //Set 1 and 1 = 1
    newData.setInput(0, 1.0f);
    newData.setInput(1, 1.0f);
    newData.setOutput(0, 0.0f);
    data.push_back(newData);

    //Set 1 and 0 = 0
    newData.setInput(0, 0.0f);
    newData.setInput(1, 0.0f);
    newData.setOutput(0, 0.0f);
    data.push_back(newData);

    //Set 0 and 0 = 0
    newData.setInput(0, 0);
    newData.setInput(1, 1);
    newData.setOutput(0, 1.0f);
    data.push_back(newData);

    //Set 0 and 1 = 0
    newData.setInput(0, 1);
    newData.setInput(1, 0);
    newData.setOutput(0, 1.0f);
    data.push_back(newData);
 
    BepAlgorithm<float> algorithm(perceptron, 0.9f);
    utils::SharedPtr< IAlgorithmListener<float> > listener(new TrainingExecutionListener<float>);
    algorithm.addListener(listener.getPtr());
    algorithm.startTraining(0.01f, data);

    perceptron->setInput(0, 0);
    perceptron->setInput(1, 0);
    perceptron->calculateOutputs();
    printf("0 0 out = %f\n", perceptron->getOutput(0));

    perceptron->setInput(0, 1);
    perceptron->setInput(1, 0);
    perceptron->calculateOutputs();
    printf("1 0 out = %f\n", perceptron->getOutput(0));

    perceptron->setInput(0, 0);
    perceptron->setInput(1, 1);
    perceptron->calculateOutputs();
    printf("0 1 out = %f\n", perceptron->getOutput(0));

    perceptron->setInput(0, 1);
    perceptron->setInput(1, 1);
    perceptron->calculateOutputs();
    printf("1 1 out = %f\n", perceptron->getOutput(0));

    perceptron->setInput(0, 1);
    perceptron->setInput(1, 1);
    perceptron->calculateOutputs();
    printf("1 1 out = %f\n", perceptron->getOutput(0));

    //Serialization
    utils::SharedPtr< IXmlVarStream<float> > varStream = new XmlVarStream<float>;
    XmlPerceptronStream<float> stream(*perceptron.getPtr(), varStream);
    std::string resultString;
    stream >> resultString;
    std::cout << resultString << endl;
    
    std::stringstream strStream( resultString );
    XmlPerceptronStream<float> newStream( strStream, varStream );
    utils::SharedPtr< PerceptronNeuralNetwork<float> > perceptron2 = new PerceptronNeuralNetwork<float> (5, new nn::SigmaEquationFactory<float>, 3);
    newStream >> *perceptron2.getPtr();
    
    XmlPerceptronStream<float> printStream(*perceptron2.getPtr(), varStream);
    printStream >> resultString; 
    std::cout << resultString;

    getchar();
    return 0;
}
// kate: indent-mode cstyle; space-indent on; indent-width 0; 
